package com.yidian.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.yidian.pojo.goods.Category;
import com.yidian.pojo.goods.Sku;
import com.yidian.pojo.order.OrderItem;
import com.yidian.server.goods.CategoryService;
import com.yidian.server.goods.SkuService;
import com.yidian.server.order.CartService;
import com.yidian.server.order.PreferentialService;
import com.yidian.utils.CacheKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author whb
 * @create 2021-08-26 10:09
 * @desciption 购物车Service实现类
 */
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Reference
    private SkuService skuService;
    @Reference
    private CategoryService categoryService;
    @Autowired
    private PreferentialService preferentialService;

    /**
     * 从redis中获取购物车信息
     * @param username 登录用户名
     * @return
     */
    @Override
    public List<Map<String, Object>> findCartList(String username) {
        System.out.println("从redis中获取"+username+"购物车信息");
        List<Map<String,Object>> cartList = (List<Map<String, Object>>) redisTemplate.boundHashOps(CacheKey.CART_LIST).get(username);
        if (cartList==null){
            cartList=new ArrayList<>();
        }
        return cartList;
    }

    /**
     * 添加商品到购物车
     * @param username 登录用户名
     * @param skuId 商品skuId
     * @param num 添加数量
     */
    @Override
    public void addItem(String username, String skuId, Integer num) {
        //实现思路： 遍历购物车，如果购物车中存在该商品则累加数量，如果不存在则 添加购物车项
        List<Map<String,Object>> cartList=findCartList(username);//获取登录用户的购物车信息
        boolean flag=false;//购物车是否存在此商品

        //遍历购物车
        for (Map<String,Object> map:cartList){
            OrderItem orderItem = (OrderItem) map.get("item");
            if (skuId.equals(orderItem.getSkuId())){
                //数量不大于0，将此商品信息从购物车中移除
                if (orderItem.getNum()<=0){
                    cartList.remove(map);
                    flag=true;
                    break;
                }

                int weight=orderItem.getWeight()/orderItem.getNum();//计算单个商品重量
                orderItem.setNum(orderItem.getNum()+num);//购物车原有数量加上变化数量
                orderItem.setMoney(orderItem.getPrice()*orderItem.getNum());//计算新金额
                orderItem.setWeight(orderItem.getNum()*weight);//计算新重量

                if (orderItem.getNum() <= 0) {
                    cartList.remove(map);
                }

                flag=true;
                break;
            }
        }

        //购物车不存在此商品
        if (flag==false){
            Sku sku = skuService.findById(skuId);//查询商品信息
            if (sku==null){
                throw new RuntimeException("商品不存在");
            }
            if (!"1".equals(sku.getStatus())){
                throw new RuntimeException("商品状态不合法");
            }
            if (num<=0){
                throw new RuntimeException("商品数量不合法");
            }

            OrderItem orderItem = new OrderItem();//创建商品订单列表对象
            orderItem.setSkuId(skuId);
            orderItem.setSpuId(sku.getSpuId());
            orderItem.setNum(num);
            orderItem.setImage(sku.getImage());
            orderItem.setPrice(sku.getPrice());
            orderItem.setName(sku.getName());
            orderItem.setMoney( orderItem.getPrice()*num );//金额计算
            if (sku.getWeight()==null){
                sku.setWeight(0);
            }
            orderItem.setWeight(sku.getWeight()*num);//重量计算

            //设置商品分类信息
            orderItem.setCategoryId3(sku.getCategoryId());//设置3级分类
            Category category3 = (Category) redisTemplate.boundHashOps(CacheKey.CATEGORY).get(sku.getCategoryId());//从redis获取3级分类对象
            if (category3==null){
                category3 = categoryService.findById(sku.getCategoryId());
                redisTemplate.boundHashOps(CacheKey.CATEGORY).put(sku.getCategoryId(),category3);
            }
            orderItem.setCategoryId2(category3.getParentId());//设置2级分类
            Category category2= (Category) redisTemplate.boundHashOps(CacheKey.CATEGORY).get(category3.getParentId());//从redis获取2级分类对象
            if (category2 == null) {
                category2=categoryService.findById(category3.getParentId());
                redisTemplate.boundHashOps(CacheKey.CATEGORY).put(category3.getParentId(),category2);
            }
            orderItem.setCategoryId1(category2.getParentId());//设置1级分类

            Map<String,Object> map=new HashMap<>();
            map.put("item",orderItem);
            map.put("checked",true);//默认选中
            cartList.add(map);
        }

        //保存购物车列表信息到redis
        redisTemplate.boundHashOps(CacheKey.CART_LIST).put(username,cartList);
    }

    /**
     * 更新选中状态
     * @param username 用户名
     * @param skuId 商品skuId
     * @param checked 商品勾选状态
     * @return
     */
    @Override
    public boolean updateChecked(String username, String skuId, boolean checked) {
        List<Map<String, Object>> cartList = findCartList(username);//获取购物车集合
        boolean isUpdate=false;
        for (Map map :cartList) {
            OrderItem orderItem = (OrderItem) map.get("item");
            //判断redis缓存的购物车信息中是否包含已购商品
            if (skuId.equals(orderItem.getSkuId())){
                map.put("checked",checked);
                isUpdate=true;//状态已更新
                break;
            }
        }

        //更新redis缓存中购物车的信息
        if (isUpdate) {
            redisTemplate.boundHashOps(CacheKey.CART_LIST).put(username,cartList);
        }
        return isUpdate;
    }

    /**
     * 删除购物车中被选中的商品
     * @param username 用户名
     */
    @Override
    public void deleteCheckedCart(String username) {
        List<Map<String, Object>> cartList = this.findCartList(username);//从redis缓存获取购物车
        cartList= cartList.stream()
                .filter(cart-> (boolean) cart.get("checked")==false)
                .collect(Collectors.toList());//使用stream流过滤掉购物车中已勾选的商品
        redisTemplate.boundHashOps(CacheKey.CART_LIST).put(username,cartList);//将未勾选的商品存入redis缓存
    }

    /**
     * 计算购物车选中商品的优惠金额
     * @param username
     * @return
     */
    @Override
    public int preferential(String username) {
        //使用stream将购物车中已选中的商品过滤出来,格式：先List<OrderItem>，最终List<Map>
        List<OrderItem> orderItemList = findCartList(username).stream()
                .filter(cart -> (boolean) cart.get("checked") == true)//过滤出已选中的商品
                .map(cart ->(OrderItem)cart.get("item"))//将map集合中的OrderItem对象选出来
                .collect(Collectors.toList());

        //按分类聚合统计每个类别商品的金额 group by
        /**
         * categoryId money
         *      1      100
         *      2      156
         *      3      837
         */
        Map<Integer, IntSummaryStatistics> cartMap = orderItemList.stream()
                .collect(Collectors.groupingBy(OrderItem::getCategoryId3, Collectors.summarizingInt(OrderItem::getMoney)));

        int allPreMoney=0;//初始化优惠金额
        //循环统计每个分类的优惠金额，并累加
        for (Integer categoryId:cartMap.keySet()){
            int money= (int) cartMap.get(categoryId).getSum();//获取每一类商品的总金额
            int preMoney = preferentialService.calcPreMoneyByCategoryId(categoryId, money);//计算每一类商品的优惠金额
            allPreMoney+=preMoney;
        }

        return allPreMoney;
    }

    /**
     * 获取最新的购物车列表（购物车商品价格和数据库商品价格同步）
     * @param username 登录用户名
     * @return
     */
    @Override
    public List<Map<String, Object>> findNewOrderItemList(String username) {
        List<Map<String, Object>> cartList = findCartList(username);//获取redis缓存中的购物车

        //循环购物车，将商品价格更新成数据库中的价格
        for (Map<String,Object> map:cartList){
            OrderItem orderItem = (OrderItem) map.get("item");
            Sku sku = skuService.findById(orderItem.getSkuId());
            orderItem.setPrice(sku.getPrice());
            orderItem.setMoney(sku.getPrice()*orderItem.getNum());
        }

        redisTemplate.boundHashOps(CacheKey.CART_LIST).put(username,cartList);//将价格和数据库同步之后的购物车列表存入到redis缓存
        return cartList;
    }
}
